package com.info.zhiduoduo.admin.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.baomidou.mybatisplus.mapper.Condition;
import com.google.common.collect.Maps;
import com.info.zhiduoduo.admin.model.formbean.crowdsource.ImportDealCrowdsourceProjectFormBean;
import com.info.zhiduoduo.admin.model.formbean.crowdsource.ImportDealCrowdsourceFormBean;
import com.info.zhiduoduo.common.constants.Constants;
import com.info.zhiduoduo.common.constants.SmartResult;
import com.info.zhiduoduo.common.constants.StatusMsg;
import com.info.zhiduoduo.common.constants.company.CompanyAccountFlowBizType;
import com.info.zhiduoduo.common.constants.company.CompanyPayType;
import com.info.zhiduoduo.common.constants.crowdsource.CrowdsourceRegfromType;
import com.info.zhiduoduo.common.constants.crowdsource.CrowdsourceUserType;
import com.info.zhiduoduo.common.constants.invoice.InvoiceType;
import com.info.zhiduoduo.common.constants.project.ProjectType;
import com.info.zhiduoduo.common.utils.NumberUtil;
import com.info.zhiduoduo.common.utils.RandomUtil;
import com.info.zhiduoduo.common.utils.StringUtil;
import com.info.zhiduoduo.core.formbean.crowdsource.AddCrowdsourceModel;
import com.info.zhiduoduo.core.listener.BaseAnalysisEventListener;
import com.info.zhiduoduo.core.service.CoreBrokerageService;
import com.info.zhiduoduo.core.service.CoreCompanyService;
import com.info.zhiduoduo.core.service.CoreCrowdsourceService;
import com.info.zhiduoduo.core.service.CoreInvoiceService;
import com.info.zhiduoduo.repository.dto.maker.StudioDetailDto;
import com.info.zhiduoduo.repository.entity.company.Company;
import com.info.zhiduoduo.repository.entity.company.CompanyAccountflow;
import com.info.zhiduoduo.repository.entity.company.CompanyParty;
import com.info.zhiduoduo.repository.entity.company.CompanyPayment;
import com.info.zhiduoduo.repository.entity.crowdsource.*;
import com.info.zhiduoduo.repository.entity.invoice.Invoice;
import com.info.zhiduoduo.repository.entity.system.TaxSource;
import com.info.zhiduoduo.repository.mapper.company.CompanyMapper;
import com.info.zhiduoduo.repository.mapper.maker.MakerStudioMapper;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tianyonghong
 * @create 2022/7/28
 */
@Getter
@Slf4j
public class UploadDealCrowdsourceProjectListener extends BaseAnalysisEventListener<ImportDealCrowdsourceProjectFormBean> {

    //解析后的数据集合
    List<ImportDealCrowdsourceProjectFormBean> list = new ArrayList<>();

    //解析后的企业集合 key:companyName
    Map<String, Company> companyMap = new HashMap<>();

    //操作人员ID
    int operateUserId;
    //智零工项目类型(1:智众包，2:智零工)
    int workType;
    //支付方式
    int payId;
    //众包城市
    Integer crowdsourceCity;
    //渠道(1:合付宝)
    Integer channel;
    //税源地ID
    Integer taxSourceId;
    CompanyMapper companyMapper;
    MakerStudioMapper makerStudioMapper;
    CoreInvoiceService coreInvoiceService;
    CoreBrokerageService coreBrokerageService;
    CoreCrowdsourceService coreCrowdsourceService;
    CoreCompanyService coreCompanyService;

    public UploadDealCrowdsourceProjectListener(ImportDealCrowdsourceFormBean importBean, MakerStudioMapper makerStudioMapper,
                                                CompanyMapper companyMapper, CoreInvoiceService coreInvoiceService,
                                                CoreBrokerageService coreBrokerageService, CoreCrowdsourceService coreCrowdsourceService,
                                                CoreCompanyService coreCompanyService) {
        this.operateUserId = importBean.getUserid();
        this.workType = importBean.getWorkType();
        this.payId = importBean.getPayId();
        this.crowdsourceCity = importBean.getCrowdsourceCity();
        this.channel = importBean.getChannel();
        this.taxSourceId = importBean.getTaxSourceId();
        this.companyMapper = companyMapper;
        this.makerStudioMapper = makerStudioMapper;
        this.coreInvoiceService = coreInvoiceService;
        this.coreBrokerageService = coreBrokerageService;
        this.coreCrowdsourceService = coreCrowdsourceService;
        this.coreCompanyService = coreCompanyService;
    }

    @Override
    public void invoke(ImportDealCrowdsourceProjectFormBean formBean, AnalysisContext analysisContext) {
        super.invoke(formBean, analysisContext);

        // 单条数据校验
        boolean result = checkValidExcelData(formBean, index);
        if (result) {
            list.add(formBean);
        }
    }

    /**
     * 数据校验
     *
     * @param formBean
     * @param index
     * @return
     */
    private boolean checkValidExcelData(ImportDealCrowdsourceProjectFormBean formBean, int index) {
        // 验证企业是否都存在
        Company company = companyMap.get(formBean.getCompname());
        if (company == null) {
            company = companyMapper.getByCompname(formBean.getCompname());
            if (company == null) {
                errorPrompt.add("请检查第[" + index + "]行数据：企业未找到");
                return false;
            }
            companyMap.put(formBean.getCompname(), company);
        }
        //记录企业ID
        formBean.setCompid(company.getCompid());

        //智众包项目需要开启智众包模式
        if (workType == Constants.WORK_TYPE_1 && !NumberUtil.equals(company.getIntelCrowdsource(), 2)) {
            errorPrompt.add("请检查第[" + index + "]行数据：企业未开通智众包业务");
            return false;
        }

        // 记录企业默认支付数据
        CompanyParty companyParty = coreCompanyService.getCompanyDefaultPartyMul(company.getCompid(), workType);
        if(companyParty == null){
            errorPrompt.add("请检查第[" + index + "]行数据：企业未配置默认业务支付方式");
            return false;
        }
        formBean.setPartyId(companyParty.getPartyId());

        //检查创客是否存在
        if (formBean.getUserType() == CrowdsourceUserType.STUDIO) {
            //验证创客是否存在
            StudioDetailDto studioDto = makerStudioMapper.getByIdno(formBean.getIdno());
            if (studioDto == null) {
                errorPrompt.add("请检查第[" + index + "]行数据：创客未找到");
                return false;
            }
            if (!studioDto.getUsername().equals(formBean.getUsername())) {
                errorPrompt.add("请检查第[" + index + "]行数据：创客工作室名称不匹配");
                return false;
            }
            if (!studioDto.getRealname().equals(formBean.getAcctName())) {
                errorPrompt.add("请检查第[" + index + "]行数据：创客姓名不匹配");
                return false;
            }
            if (!studioDto.getAcctno().equals(formBean.getAcctno())) {
                errorPrompt.add("请检查第[" + index + "]行数据：创客收款方账户不匹配");
                return false;
            }
            //记录创客用户ID
            formBean.setUserid(studioDto.getUserid());

        } else if (formBean.getUserType() == CrowdsourceUserType.NATURAL_PERSON) {
            //查询自然人
            List<CrowdsourceAccount> accounts = new CrowdsourceAccount().selectList(Condition.create()
                                                                                             .eq("idno", formBean.getIdno())
                                                                                             .eq("realname", formBean.getAcctName())
                                                                                             .eq("acctno", formBean.getAcctno()));
            if (CollectionUtils.isNotEmpty(accounts)) {
                //存在 记录自然人用户ID
                formBean.setUserid(accounts.get(0).getCrowdsourceid());
            }
        } else {
            errorPrompt.add("请检查第[" + index + "]行数据：用户类型错误");
            return false;
        }

        return true;
    }
    private Integer operatingSubject(String name) {
        Map<String,Integer> map = Maps.newHashMap();
        map.put("天津四如科技发展有限公司",1);
        map.put("江西武圣信息科技有限公司",2);
        map.put("智圣（天津）网络科技有限公司",3);
        map.put("芜湖信圣科技发展有限公司",4);
        map.put("徐州法圣信息技术有限公司",5);
        map.put("宁波美圣科技发展有限公司",6);
        map.put("芜湖英圣集群注册托管有限公司",7);
        map.put("宁夏明圣科技发展有限公司",8);
        map.put("上海秀圣信息技术有限公司",9);
        map.put("盐城如山数字科技有限公司",10);
        map.put("河南冉澄信息科技有限公司",11);
        return map.get(name);
    }
    /**
     * 新建自然人
     *
     * @return
     */
    private Crowdsource createCrowdSource(ImportDealCrowdsourceProjectFormBean bean) {
        int regForm = CrowdsourceRegfromType.CROWDSOURCE_PROJECT;
        if (workType == Constants.WORK_TYPE_2) {
            regForm = CrowdsourceRegfromType.CONTRACTOR_PROJECT;
        }

        AddCrowdsourceModel model = new AddCrowdsourceModel().setIdno(bean.getIdno())
                                                             .setPhone(bean.getPhone())
                                                             .setRealname(bean.getAcctName())
                                                             .setBankname(bean.getBankname())
                                                             .setAcctno(bean.getAcctno())
                                                             .setBindcompid(bean.getCompid())
                                                             .setRegfrom(regForm);
        if (null == bean.getUserid()){
            return coreCrowdsourceService.addCrowdsource(model);
        }
        model.setUserid(bean.getUserid());
        return coreCrowdsourceService.modifyCrowdsource(model);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 有失败的数据，则返回
        if (CollectionUtils.isNotEmpty(errorPrompt)) {
            smartResult = SmartResult.fail(StatusMsg.StatusMsg_1109, errorPrompt);
            return;
        }
        if (CollectionUtils.isEmpty(list)){
            smartResult = SmartResult.ofEmptyData();
            return;
        }
        // 校验企业导入金额
        SmartResult balanceResult = checkCompanyBalance();
        if(balanceResult.isFailed()){
            smartResult = balanceResult;
            return;
        }
        // 执行导入数据
        createData();
        smartResult = SmartResult.success();
    }

    public SmartResult checkCompanyBalance() {
        // 按企业名分组
        Map<String, List<ImportDealCrowdsourceProjectFormBean>> map = list.stream().collect(Collectors.groupingBy(ImportDealCrowdsourceProjectFormBean::getCompname));
        for (Map.Entry<String, List<ImportDealCrowdsourceProjectFormBean>> entry : map.entrySet()) {

            Company company = companyMap.get(entry.getKey());
            // 获取企业余额
            CompanyPayment companyPayment = coreCompanyService.getCompanyPayment(company.getCompid(), this.payId);
            if (companyPayment == null) {
                return SmartResult.fail(StatusMsg.StatusMsg_330);
            }

            double totalProjectAmount = entry.getValue().stream().map(ImportDealCrowdsourceProjectFormBean::getItemAmount).reduce(Double::sum).orElse(0d);
            double totalTaxFee = entry.getValue().stream().map(ImportDealCrowdsourceProjectFormBean::getTaxFee).reduce(Double::sum).orElse(0d);
            double totalServiceCharge = entry.getValue().stream().map(ImportDealCrowdsourceProjectFormBean::getServiceCharge).reduce(Double::sum).orElse(0d);
            BigDecimal projectTotalPayableAmount = BigDecimal.valueOf(totalProjectAmount + totalTaxFee + totalServiceCharge);
            // 检查企业余额是否足够
            if (companyPayment.getBalance().compareTo(projectTotalPayableAmount) < 0) {
                //余额不足,返回报错
                return SmartResult.fail(StatusMsg.StatusMsg_365);
            }
        }
        return SmartResult.success();
    }

    /**
     * 导入数据
     */
    public void createData() {
        //查询税源地税率
        BigDecimal taxSourceCostRate = BigDecimal.ZERO;
        if (this.taxSourceId != null) {
            TaxSource taxSource = new TaxSource().selectById(this.taxSourceId);
            taxSourceCostRate = taxSource != null ? taxSource.getTaxSourceCostRate() : BigDecimal.ZERO;
        }

        // 按企业名分组, 接着再看项目名分组
        Map<String, Map<String, List<ImportDealCrowdsourceProjectFormBean>>> map = list.stream()
                                                                                       .collect(Collectors.groupingBy(ImportDealCrowdsourceProjectFormBean::getCompname,
                                                                                           Collectors.groupingBy(ImportDealCrowdsourceProjectFormBean::getProjectName)));
        for (Map.Entry<String, Map<String, List<ImportDealCrowdsourceProjectFormBean>>> entry : map.entrySet()) {

            Company company = companyMap.get(entry.getKey());

            // 获取企业余额
            CompanyPayment companyPayment = coreCompanyService.getCompanyPayment(company.getCompid(), this.payId);
            if(companyPayment == null){
                smartResult = SmartResult.fail(StatusMsg.StatusMsg_330);
                return;
            }

            Map<String, List<ImportDealCrowdsourceProjectFormBean>> projectMap = entry.getValue();
            for (Map.Entry<String, List<ImportDealCrowdsourceProjectFormBean>> projectEntry : projectMap.entrySet()) {
                String projectName = projectEntry.getKey();
                List<ImportDealCrowdsourceProjectFormBean> projectList = projectEntry.getValue();
                double totalProjectAmount = projectList.stream()
                                                       .map(ImportDealCrowdsourceProjectFormBean::getItemAmount)
                                                       .reduce(Double::sum)
                                                       .orElse(0d);
                double totalTaxFee = projectList.stream()
                                                .map(ImportDealCrowdsourceProjectFormBean::getTaxFee)
                                                .reduce(Double::sum)
                                                .orElse(0d);
                double totalServiceCharge = projectList.stream()
                                                       .map(ImportDealCrowdsourceProjectFormBean::getServiceCharge)
                                                       .reduce(Double::sum)
                                                       .orElse(0d);
                BigDecimal projectTotalPayableAmount = BigDecimal.valueOf(totalProjectAmount + totalTaxFee + totalServiceCharge);

                // 项目数据
                ImportDealCrowdsourceProjectFormBean formBean = projectList.get(0);
                CrowdsourceProject project = formBean.toEntity(company, formBean);
                Double baseTaxRate = workType == Constants.WORK_TYPE_1 ? company.getBaseTaxRate() : company.getBaseTaxRateOdd();

                project.setProjectName(projectName)
                       .setPeopleCount(projectList.size())
                       .setProjectTotalAmount(BigDecimal.valueOf(totalProjectAmount))
                       .setProjectTotalServiceCharge(BigDecimal.valueOf(totalTaxFee + totalServiceCharge))
                       .setProjectTotalPayableAmount(projectTotalPayableAmount)
                       .setProjectTotalInvoiceAmount(projectTotalPayableAmount)
                       .setSupplementPersonnel(operateUserId)
                       .setWorkType(workType)
                       .setCrowdsourceCity(crowdsourceCity)
                       .setChannel(channel)
                       .setTaxSourceId(taxSourceId)
                       .setTaxSourceCostRate(taxSourceCostRate)
                       .setBaseTaxRate(baseTaxRate)
                       .setPayId(this.payId)
                       .setPartyId(operatingSubject(formBean.getOperatingSubject()));
                boolean insert = project.insert();

                /** 企业余额扣款 生成企业流水 start */
                BigDecimal beforeBalance = companyPayment.getBalance();
                BigDecimal currBalance = companyPayment.getBalance().subtract(project.getProjectTotalPayableAmount());
                //企业余额修改
                companyPayment.setBalance(currBalance).updateById();
                CompanyAccountflow accountflow = new CompanyAccountflow()
                        .setCompid(project.getCompid())
                        .setBizid(project.getProjectid())
                        .setBizType(project.getWorkType() == Constants.WORK_TYPE_1 ? CompanyAccountFlowBizType.CROWDSOURCE_PROJECT : CompanyAccountFlowBizType.CROWDSOURCE_ODD_PROJECT)
                        .setFlowname(project.getWorkType() == Constants.WORK_TYPE_1 ? "智众包项目款" : "智零工项目款")
                        .setFlowtype(2)
                        .setFlowAmount(project.getProjectTotalPayableAmount())
                        .setBeforeBalance(beforeBalance)
                        .setCurrBalance(currBalance)
                        .setBeforeFrozenBalance(companyPayment.getFrozenBalance())
                        .setCurrFrozenBalance(companyPayment.getFrozenBalance())
                        .setPayId(this.payId);
                accountflow.insert();
                /** 企业余额扣款 生成企业流水 end */

                // 插入项目,处理单个自然人的项目金额
                if (insert) {
                    // 补录发票
                    Date now = new Date();
                    Invoice invoice = coreInvoiceService.createCrowdsourceProjectInvoice(project.getProjectid());
                    invoice.setInvoicetype(StringUtil.toInt(project.getInvoiceType()))
                           .setContent(project.getInvoiceContent())
                           .setState(Constants.invoicestate_2)
                           .setApplyTime(now)
                           .setAccepttime(now)
                           .setCreatetime(project.getFinishtime())
                           .setFinishtime(project.getFinishtime())
                           .setSupplementPersonnel(operateUserId)
                           .setSupplementTime(now)
                           .setWhetherSupplement(Constants.TRUE);
                    invoice.updateById();

                    // 智零工类型需要生成到智零工发票表
                    if (NumberUtil.equals(Constants.WORK_TYPE_2, workType)) {
                        ContractorInvoice contractorInvoice = coreInvoiceService.createContractorInvoice(project.getProjectid());
                        contractorInvoice.setCreatetime(project.getFinishtime());
                        contractorInvoice.updateById();
                    }

                    // 交易数据
                    CrowdsourceTradeRecord tradeRecord = new CrowdsourceTradeRecord().setProjectid(project.getProjectid())
                                                                                     .setBatchNo(RandomUtil.createRandomNo("IMP_BATCH_PAY_", ""))
                                                                                     .setBatchStatus(Constants.CROWDSOURE_BATCH_TRADE_BATCH_FINISHED)
                                                                                     .setFinishtime(formBean.getFinishtime())
                                                                                     .setTotalCount(projectList.size())
                                                                                     .setTotalSuccCount(projectList.size())
                                                                                     .setTotalSuccAmount(BigDecimal.valueOf(totalProjectAmount))
                                                                                     .setCompid(company.getCompid())
                                                                                     .setCreatetime(formBean.getCreatetime())
                                                                                     .setPayId(CompanyPayType.PLATFORM_OFFLINE);
                    tradeRecord.insert();

                    // 准备确定合伙人分佣列表
                    coreBrokerageService.prepareProjectBrokerage(company.getCompid(), 0, project.getProjectid(),
                            ProjectType.CROWDSOURCE);
                    // 插入单条明细
                    projectList.forEach(fb -> {
                        //自然人数据创建
                        if(fb.getUserType() == CrowdsourceUserType.NATURAL_PERSON){
                            Crowdsource crowdsource = createCrowdSource(fb);
                            fb.setUserid(crowdsource.getCrowdsourceid());
                        }

                        // 项目明细
                        CrowdsourceProjectItem projectItem = new CrowdsourceProjectItem().setUserid(fb.getUserid())
                                                                                         .setUserType(fb.getUserType())
                                                                                         .setUsername(fb.getUsername())
                                                                                         .setRealname(fb.getAcctName())
                                                                                         .setProjectid(project.getProjectid())
                                                                                         .setProjectServiceCharge(BigDecimal.valueOf(fb.getTaxFee() + fb.getServiceCharge()))
                                                                                         .setProjectAmount(BigDecimal.valueOf(fb.getItemAmount()))
                                                                                         .setIntegratedTaxFee(BigDecimal.valueOf(fb.getItemAmount() + fb.getTaxFee() + fb.getServiceCharge()))
                                                                                         .setCreatetime(formBean.getCreatetime());
                        projectItem.insert();

                        // 交易明细
                        CrowdsourceTradeRecordItem tradeRecordItem = new CrowdsourceTradeRecordItem().setAcctname(fb.getAcctName())
                                                                                                     .setAcctno(fb.getAcctno())
                                                                                                     .setAccttype(StringUtil.toInt(fb.getAccttype()))
                                                                                                     .setBankname(formBean.getBankno())
                                                                                                     .setBankno(fb.getBankno())
                                                                                                     .setBatchId(tradeRecord.getBatchId())
                                                                                                     .setBatchNo(tradeRecord.getBatchNo())
                                                                                                     .setProjectid(project.getProjectid())
                                                                                                     .setProjectItemId(projectItem.getId())
                                                                                                     .setPurpose(fb.getPurpose())
                                                                                                     .setRemark(fb.getRemark())
                                                                                                     .setStatus(Constants.CROWDSOURCE_BATCH_ITEM_PAID)
                                                                                                     .setTradeamount(BigDecimal.valueOf(fb.getItemAmount()))
                                                                                                     .setTradeNo(RandomUtil.createRandomNo("IMP_PAY_", ""))
                                                                                                     .setTradetime(new Date())
                                                                                                     .setCreatetime(formBean.getCreatetime())
                                                                                                     .setFinishtime(formBean.getFinishtime());
                        tradeRecordItem.insert();

                        // 补录成本发票
                        if (NumberUtil.equals(Constants.WORK_TYPE_1, workType)) {
                            CrowdsourceInvoice crowdsourceInvoice = coreInvoiceService.createCrowdsourceProjectMakerInvoice(
                                    projectItem.getId());
                            // 成本发票是普票
                            crowdsourceInvoice.setInvoiceType(String.valueOf(InvoiceType.GENERAL))
                                              .setGongQingInvoiceContent(project.getInvoiceContent())
                                              .setCreatetime(project.getFinishtime())
                                              .setSupplementTime(new Date())
                                              .setSupplementPersonnel(operateUserId)
                                              .setWhetherSupplement(1);
                            crowdsourceInvoice.updateById();
                        }
                    });

                    // 处理合伙人分佣金额
                    coreBrokerageService.handleCrowdsourceProjectPartnerBrokerage(tradeRecord, project);
                }
            }
        }
    }

}
